# 起手式
import numpy as np
array 裡面必須是同一種資料型態
a = np.array([1,2,3,4]); print(a, repr(a))
b = np.array([1,2,3,'abc']); print(b, repr(b))
c = np.array([1,2,3,'abc', ['cde', 123]]); print(c)
a[2]
a[2] = 999; a[2]
x = np.array([1,2,3,4])
y = np.array([[1.,2,3],[4,5,6]])
y
y[1, 0]
看 ndarray 的第一件事情: shape , dtype
x.shape
y.shape # 原始建構 list 的層級由外往內的 dimension
x.dtype
y.dtype
# import matplotlib
%matplotlib inline
from matplotlib import pyplot as plt
plt.style.use('ggplot')
# 畫圖
plt.plot(x, 'x');
# 建立 0 array
np.zeros_like(y)
np.zeros((10,10))
np.ones((3, 3, 2))
# 跟 range 差不多
x = np.arange(0, 10, 0.1); x
# 亂數
y = np.random.uniform(-1,1, size=x.shape)
plt.plot(x, y)
# 亂數
x = np.arange(0, 10, 0.1)
y = np.random.normal(-1,1, size=x.shape); print(x.shape)
print(y)
plt.figure(figsize=(10,4))
plt.subplot(121)
plt.plot(x, y)
plt.subplot(122)
plt.plot(np.ones_like(y), y, 'o')
這是一堆資料
see also np.vectorize
np.array([1, 2, 3]) * np.array([100, 200])
np.array([1, 2, 3]) * np.array([100, 200, 300])
x = np.linspace(0, 2* np.pi, 1000) # 0~2pi 平均切 1000 個點
plt.plot(x, np.sin(x))
x = np.linspace(-2, 2, 30)
y = x**2 + 1
print(plt.style.available)
with plt.style.context((['fivethirtyeight'])):
plt.plot(x, y, '', x, y, 'o')
# 或者看看參考範例
# %run q0.py
# %load q0.py
x = np.linspace(-1,1,11)
plt.plot(x, x**2+1, "g^", x, x**3, 'ro', x, x**2+1, 'b');
試試看圖片。 使用
from PIL import Image
# 讀入 PIL Image (這張圖是從 openclipart 來的 cc0)
img = Image.open('img/Green-Rolling-Hills-Landscape-800px.png')
# 圖片轉成 ndarray
img_array = np.array(img)
# ndarray 轉成 PIL Image
Image.fromarray(img_array)
看看這個圖片的內容, dtype 和 shape
# 參考答案
# %load q1.py
from PIL import Image
img = Image.open('img/Green-Rolling-Hills-Landscape-800px.png')
img_array = np.array(img)
print("img_array.shape={}".format(img_array.shape))
print("img_array.dtype={}".format(img_array.dtype))
Image.fromarray(img_array)
可以用類似 list 的 indexing
a = np.arange(30)
a
a[5]
a[3:7]
# 列出所有奇數項
a[1::2]
# 還可以用來設定值
a[1::2] = -1
a
# 或是
a[1::2] = -a[::2]-1
a
%run -i q2.py
#%load q2.py
x = np.arange(30); print(x.shape)
a = np.arange(30)
a[1::2] = -a[1::2]
px = x[0::2]
py = x[0::2]; print(py.shape)
qx = x[1::2]
qy = -x[1::2]; print(qy.shape)
with plt.style.context('bmh'):
plt.plot(x, a, '', px, py, 'x', qx, qy, 'v')
b = np.array([[1,2,3], [4,5,6], [7,8,9]])
b
b[1][2]
b[1,2] # 1,2 本身就是 tuple
b[(1,2)]
b[1]
b[1,:]
from pprint import pprint
pprint(img_array[:,:, 2]) # blue channel
Image.fromarray(img_array[:,:, 2])
b = np.random.randint(0,99, size=(10,10))
print(b[::2, 2])
# slice 物件
print(b[slice(0, 10, 2), 2])
物件會 copying
np.random.seed(1)
b = np.random.randint(0,99, size=(5,10))
b
試試看下面的結果
想一下是怎麼一回事(numpy 在想什麼?)
b[[1,3]] # == b[([1,3],)] 利用 list 做 indexing
np.array_equal( b[[1,3]], b[([1,3],)] )
b[(1,3)] # == b[1,3]
b[[1,2],
[3,4]] # 先篩 d1 的 1,2,再篩 d2 的 3,4
b[[(1,2),
(3,4)]] # 同上,先篩 d1 的 1,2,再篩 d2 的 3,4
b[[1,2]][:,[3,4]] # 同時篩 d1: (1, 3), d2: (3,4)
b[[True, False, False, True, False]]
print(b)
b[:, np.arange(10) % 3 == 0]
把 b 中的偶數都變成 -1
#參考範例
%run -i q4.py
b = np.random.randint(0,99, size=(5,10)); print('id of b: {}'.format(id(b)))
pprint(b)
b[b % 2 == 0] = -1; print('id of b: {}'.format(id(b)))
pprint(b)
# 還記得剛才的
from PIL import Image
img = Image.open('img/Green-Rolling-Hills-Landscape-800px.png')
img_array = np.array(img)
Image.fromarray(img_array)
# 用來顯示圖片的函數
from IPython.display import display
def show(img_array):
display(Image.fromarray(img_array))
from urllib.request import urlopen
url = "https://raw.githubusercontent.com/playcanvas/engine/master/examples/images/animation.png"
simg = Image.open(urlopen(url))
Y=0.299R+0.587G+0.114B # 將圖片縮小成一半
%run -i q_half.py
# 將圖片放大
# %run -i q_scale2.py
from urllib.request import urlopen
url = "https://raw.githubusercontent.com/playcanvas/engine/master/examples/images/animation.png"
simg = Image.open(urlopen(url))
simg_array = np.array(simg)
print("原始大小")
show(simg_array)
print("增高兩倍")
simg_array_h2 = simg_array[[i//2 for i in range(2*simg_array.shape[0])],:]
show(simg_array_h2)
print("增寬兩倍")
simg_array_w2 = simg_array[:, [i//2 for i in range(2*simg_array.shape[1])]]
show(simg_array_w2)
print("放大兩倍")
x_idx = [i//2 for i in range(2*simg_array.shape[0])]
y_idx = [i//2 for i in range(2*simg_array.shape[1])]
simg_array_2 = simg_array[x_idx][:,y_idx]
show(simg_array_2)
# 圖片上下顛倒
show(img_array[::-1])
# %run -i q_paste.py
simg_array = np.array(simg); #print(simg_array)
img_array2 = img_array.copy()
print("簡單的")
img_array2[200:400, 300:500] = simg_array
show(img_array2)
print("這樣呢?")
img_array2 = img_array.copy()
# print(np.apply_along_axis(lambda a: np.sum(a[:3]), 2, simg_array))
is_black = np.apply_along_axis(lambda a: np.sum(a[:3]), 2, simg_array) > 10; print(is_black)
img_array2[200:400, 300:500][is_black] = simg_array[is_black]
show(img_array2)
%run -i q_grayscale.py
# 用迴圈畫圓
%run -i q_slow_circle.py
# 用 fancy index 畫圓
%run -i q_fast_circle.py
x = np.arange(800).reshape(1, -1); print(x.shape)
y = np.arange(530).reshape(-1, 1); print(y.shape)
print((x + y).shape) # broadcasting
in_circle = (x-400)**2 + (y-100)**2 <- 80**2 # broadcasting circle
# 還可以做模糊化
a = img_array.astype(float)
for i in range(10):
a[1:,1:] = (a[1:,1:]+a[:-1,1:]+a[1:,:-1]+a[:-1,:-1])/4
show(a.astype('uint8'))
# 求邊界
a = img_array.astype(float)
a = a @ [0.299, 0.587, 0.114, 0]
a = np.abs((a[1:]-a[:-1]))*2
show(a.astype('uint8'))
.flatten 拉平看看資料在電腦中如何儲存?
查看 .reshape, .T, np.rot00, .swapaxes .rollaxis
然後再做一下上面的事情
.T: 最後兩軸交換swapaxes: 交換軸moveaxis: 移動軸位置rollaxis: 軸往前往後移動A = np.random.randint(0, 10, size=(6,6))
A
print(A.flatten()) # copy
A.ravel()
print(A)
A.reshape((2,2,3,-1))
# reshaping 的應用
R,G,B,A = img_array.reshape(-1,4).T
plt.hist((R,G,B,A), color="rgbk");
# 例子
show(np.hstack([img_array, img_array2]))
# 例子
np.concatenate([img_array, img_array2], axis=2).shape
np.max([1,2,3,4])
np.sum([1,2,3,4])
np.mean([1,2,3,4])
np.min([1,2,3,4])
np.argmax([2,1,5,4])
多重意義的運用, 水平平均,整合垂直平均
x_mean = img_array.astype(float).min(axis=0, keepdims=True)
print(x_mean.dtype, x_mean.shape)
y_mean = img_array.astype(float).min(axis=1, keepdims=True)
print(y_mean.dtype, y_mean.shape)
# 自動 broadcast
xy_combined = ((x_mean+y_mean)/2).astype('uint8')
show(xy_combined)
x = np.zeros((3,4,5))
print(x[None, :, :, :].shape) # 增維
print(x[:, None, :, :].shape) # 增維
print(x[:, None, ..., np.newaxis].shape) # 增維
先從點積開始
# = 1*4 + 2*5 + 4*6
np.dot([1,2,3], [4,5,6])
u=np.array([1,2,3])
v=np.array([4,5,6])
print( u@v ) # 矩陣乘法 np.matmult
print(np.matmul(u,v))
print( (u*v).sum() )
如果忘記矩陣乘法是什麼了, 參考這裡 http://matrixmultiplication.xyz/ 或者 http://eli.thegreenplace.net/2015/visualizing-matrix-multiplication-as-a-linear-combination/
矩陣乘法可以看成是:
np.sum(a[:,:, np.newaxis] * b[np.newaxis, : , :], axis=1)
dot(a, b)[i,k] = sum(a[i,:] * b[:, k])
要如何推廣?
np.sum(a[..., np.newaxis] * b[np.newaxis, ...], axis=(1, 2))
tensordot(a,b)[i,k]=sum(a[i, ...]* b[..., k])
https://en.wikipedia.org/wiki/Tensor_contraction
dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
np.tensordot(a,b, axes=(-1,-2))
a=np.random.random(size=(3,4,5))
b=np.random.random(size=(3,5,7))
(a @ b).shape
np.sum(a[..., np.newaxis] * np.moveaxis(b[..., np.newaxis], -1,-3), axis=-2)
np.einsum('ii', a) # trace(a)
np.einsum('ii->i', a) #diag(a)
np.einsum('ijk,jkl', a, b) # tensordot(a,b)
np.einsum('ijk,ikl->ijl', a,b ) # matmul(a,b)
A=np.random.randint(0,10, size=(5,3))
A
B=np.random.randint(0,10, size=(3,7))
B
A.dot(B).shape
np.matmul(A, B).shape
np.multiply(A, A)
C = np.random.randint(0, 10, size=(3,5,6))
D = np.random.randint(0, 10, size=(5,6,7))
np.tensordot(C, D, axes=2).shape # (default) tensor double contraction
numpy 以 ndarray 為中心
np.vectorize把一般的函數變成逐項運算 )